package ru.paswd.marketprice.rest.app.services;

import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import ru.paswd.marketprice.rest.api.exceptions.IncorrectProductCategoryException;
import ru.paswd.marketprice.rest.app.entity.Price;
import ru.paswd.marketprice.rest.app.entity.Product;
import ru.paswd.marketprice.rest.app.entity.ProductCategory;
import ru.paswd.marketprice.rest.app.mappers.ProductCategoryMapper;
import ru.paswd.marketprice.rest.app.mappers.ProductMapper;
import ru.paswd.marketprice.rest.app.repositories.PricesRepository;
import ru.paswd.marketprice.rest.app.repositories.ProductCategoriesRepository;
import ru.paswd.marketprice.rest.app.repositories.ProductsRepository;
import ru.paswd.marketprice.rest.app.utils.ListUtils;

import java.util.List;

@Service
@RequiredArgsConstructor
public class ProductService {

    private final ProductsRepository productsRepository;
    private final PricesRepository pricesRepository;
    private final ProductCategoriesRepository productCategoriesRepository;
    private final ProductMapper productMapper;
    private final ProductCategoryMapper productCategoryMapper;

    public List<ru.paswd.marketprice.rest.api.dto.ProductCategory> getProductCategories() {
        return ListUtils.mapToList(productCategoriesRepository.findAll(), productCategoryMapper::toDto);
    }

    public Page<ru.paswd.marketprice.rest.api.dto.Product> getProducts(
            String name, String category, Pageable pageable) {

        Page<Product> products;

        if (category != null) {
            ProductCategory productCategory = productCategoriesRepository
                    .findByName(category)
                    .orElseThrow(IncorrectProductCategoryException::new);

            if (name == null) {
                products = productsRepository.findAllByCategory(productCategory, pageable);
            } else {
                products = productsRepository.findAllByNameContainsAndCategory(
                        name, productCategory, pageable);
            }
        } else {
            if (name == null) {
                products = productsRepository.findAll(pageable);
            } else {
                products = productsRepository.findAllByNameContains(name, pageable);
            }
        }

        return products.map(p -> productMapper.toDto(
                p, getPriceMin(p), getPriceMax(p)));
    }

    private Integer getPriceMin(Product product) {
        return pricesRepository.findFirstByProductOrderByPriceAsc(product)
                .map(Price::getPrice)
                .orElse(null);
    }

    private Integer getPriceMax(Product product) {
        return pricesRepository.findFirstByProductOrderByPriceDesc(product)
                .map(Price::getPrice)
                .orElse(null);
    }
}
